/*
 * MIT License
 *
 * Copyright (c) 2023-present, tangli
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package tony.test.mybatis.datascope.unit

import jakarta.annotation.Resource
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.springframework.test.context.ActiveProfiles
import tony.mybatis.datascope.IDataScopeContext
import tony.mybatis.datascope.interceptor.ScopedDataPermissionInterceptor
import tony.mybatis.datascope.model.ScopedColumn
import tony.test.mybatis.datascope.DataScopeBaseTest

/**
 * 数据权限拦截器正确性测试
 * @author tangli
 * @date 2025/09/21 10:00
 */
@ActiveProfiles("mysql")
@DisplayName("数据权限拦截器正确性测试")
class ScopedDataPermissionInterceptorTest : DataScopeBaseTest() {

    @Resource
    private lateinit var dataScopeContext: IDataScopeContext

    @Resource
    private lateinit var interceptor: ScopedDataPermissionInterceptor

    @Nested
    @DisplayName("SELECT语句正确性验证")
    inner class SelectCorrectnessTest {

        @Test
        @DisplayName("基础SELECT:权限条件正确注入")
        fun testBasicSelectCorrectness() {
            val originalSql = "SELECT * FROM sys_dict"

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 基础SELECT正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            assertTrue(result.contains("creator_id = 'user1'"))
            assertFalse(result.contains("creator_org_id"))
        }

        @Test
        @DisplayName("带别名SELECT:权限条件正确注入到别名")
        fun testSelectWithAliasCorrectness() {
            val originalSql = "SELECT * FROM sys_dict d"

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 带别名SELECT正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            assertTrue(result.contains("d.creator_id = 'user1'"))
        }

        @Test
        @DisplayName("复杂SELECT:多条件组合正确")
        fun testComplexSelectCorrectness() {
            val originalSql = "SELECT * FROM sys_dict d WHERE d.dict_name = 'test'"

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1", "user2"))
                .orgIdList(listOf("org1"))
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 复杂SELECT正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            // 验证最终生成的SQL包含权限条件
            assertTrue(result.contains("creator_id IN ('user1', 'user2')"))
            assertTrue(result.contains("creator_org_id = 'org1'"))
            assertTrue(result.contains("OR"))
            assertTrue(result.contains("dict_name = 'test'"))
            assertTrue(result.contains("AND"))
        }

        @Test
        @DisplayName("JOIN查询:权限条件正确注入")
        fun testJoinSelectCorrectness() {
            val originalSql = """
                SELECT d.*, t.dict_type_name
                FROM sys_dict d
                LEFT JOIN sys_dict_type t ON d.dict_type_id = t.dict_type_id
                WHERE d.dict_name LIKE '%test%'
            """.trimIndent()

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== JOIN查询正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            assertTrue(result.contains("d.creator_id = 'user1'"))
            assertTrue(result.contains("LEFT JOIN"))
            assertTrue(result.contains("dict_name LIKE '%test%'"))
        }

        @Test
        @DisplayName("子查询:权限条件正确注入")
        fun testSubquerySelectCorrectness() {
            val originalSql = """
                SELECT * FROM sys_dict d
                WHERE d.dict_type_id IN (
                    SELECT dict_type_id FROM sys_dict_type WHERE dict_type_code = 'STATUS'
                )
            """.trimIndent()

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 子查询正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            assertTrue(result.contains("d.creator_id = 'user1'"))
            assertTrue(result.contains("dict_type_code = 'STATUS'"))
        }
    }

    @Nested
    @DisplayName("UPDATE/DELETE正确性验证")
    inner class UpdateDeleteCorrectnessTest {

        @Test
        @DisplayName("UPDATE语句:正确注入到第一个表")
        fun testUpdateCorrectness() {
            val originalSql = "UPDATE sys_dict SET dict_name = 'updated' WHERE dict_id = '1'"

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .call {
                    interceptor.parserMulti(originalSql, "test.update")
                }

            logger.info("=== UPDATE正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            // 验证正确注入权限条件
            assertTrue(result.contains("creator_id = 'user1'"))
            assertTrue(result.contains("dict_id = '1'"))
            assertTrue(result.contains("AND"))
        }

        @Test
        @DisplayName("DELETE语句:正确注入到第一个表")
        fun testDeleteCorrectness() {
            val originalSql = "DELETE FROM sys_dict WHERE dict_name LIKE '%test%'"

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .orgIdList(listOf("org1"))
                .call {
                    interceptor.parserMulti(originalSql, "test.delete")
                }

            logger.info("=== DELETE正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            // 验证正确注入权限条件
            assertTrue(result.contains("creator_id = 'user1'") || result.contains("creator_org_id = 'org1'"))
            assertTrue(result.contains("dict_name LIKE '%test%'"))
            assertTrue(result.contains("AND"))
        }

        @Test
        @DisplayName("复杂UPDATE:带子查询的UPDATE")
        fun testComplexUpdateCorrectness() {
            val originalSql = """
                UPDATE sys_dict d
                SET d.dict_name = 'updated'
                WHERE d.dict_id IN (
                    SELECT dict_id FROM sys_dict_type t
                    WHERE t.dict_type_code = 'STATUS'
                )
            """.trimIndent()

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .call {
                    interceptor.parserMulti(originalSql, "test.update")
                }

            logger.info("=== 复杂UPDATE正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            assertTrue(result.contains("creator_id = 'user1'"))
            assertTrue(result.contains("dict_type_code = 'STATUS'"))
        }
    }

    @Nested
    @DisplayName("表过滤功能正确性验证")
    inner class TableFilterFunctionCorrectnessTest {

        @Test
        @DisplayName("排除表功能:正确跳过排除的表")
        fun testExcludeTableFunctionCorrectness() {
            val originalSql = "SELECT * FROM sys_dict"

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .excludeTableNames(listOf("sys_dict"))
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 排除表功能正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            // 验证跳过处理（表被排除）
            assertEquals(originalSql, result)
        }

        @Test
        @DisplayName("包含表功能:正确处理包含的表")
        fun testIncludeTableFunctionCorrectness() {
            val originalSql = "SELECT * FROM sys_dict"

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .includeTableNames(listOf("sys_dict"))
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 包含表功能正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            // 验证处理表（表在包含列表中）
            assertTrue(result.contains("creator_id = 'user1'"))
        }

        @Test
        @DisplayName("自定义列映射功能:正确使用自定义列")
        fun testCustomColumnFunctionCorrectness() {
            val originalSql = "SELECT * FROM sys_dict d"
            val customColumn = ScopedColumn("d", "custom_user_id", "custom_org_id")

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1"))
                .orgIdList(listOf("org1"))
                .scopedColumns(listOf(customColumn))
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 自定义列映射功能正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            // 验证使用自定义列名
            assertTrue(result.contains("d.custom_user_id = 'user1'"))
            assertTrue(result.contains("d.custom_org_id = 'org1'"))
            assertFalse(result.contains("creator_id"))
            assertFalse(result.contains("creator_org_id"))
        }
    }

    @Nested
    @DisplayName("边界条件集成正确性验证")
    inner class BoundaryConditionIntegrationTest {

        @Test
        @DisplayName("无权限条件:正确跳过处理")
        fun testNoPermissionConditionCorrectness() {
            val originalSql = "SELECT * FROM sys_dict"

            val result = dataScopeContext.dataScope()
                .userIdList(emptyList())
                .orgIdList(emptyList())
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 无权限条件正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            // 验证不注入任何权限条件
            assertEquals(originalSql, result)
        }

        @Test
        @DisplayName("复合条件:多种配置组合正确性")
        fun testComplexConditionCombinationCorrectness() {
            val originalSql = "SELECT * FROM sys_dict d WHERE d.build_in = 1"

            val result = dataScopeContext.dataScope()
                .userIdList(listOf("user1", "user2"))
                .orgIdList(listOf("org1"))
                .excludeTableNames(listOf("sys_user"))  // 不影响sys_dict
                .call {
                    interceptor.parserSingle(originalSql, "test.select")
                }

            logger.info("=== 复合条件正确性验证 ===")
            logger.info("原始SQL: {}", originalSql)
            logger.info("最终SQL: {}", result)

            // 验证所有条件正确组合
            assertTrue(result.contains("d.creator_id IN ('user1', 'user2')"))
            assertTrue(result.contains("d.creator_org_id = 'org1'"))
            assertTrue(result.contains("OR"))
            assertTrue(result.contains("d.build_in = 1"))
            assertTrue(result.contains("AND"))
        }
    }
}
